#pragma once

#include"Thread.hpp"
#include <iostream>
#include <vector>
#include <queue>
#include <mutex>
#include <pthread.h>
#include <unistd.h>

static const int N = 5;

//V2版本：使用自己封装的线程
template <class T>
class ThreadPool
{
public:
    ThreadPool(int num = N) : _num(num)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    //线程初始化
    void init()
    {
        for(int i=0;i<_num;++i)
        {
            _threads.push_back(Thread(i,runRountine,this));
        }
    }

    //线程启动
    void start()
    {
        for(auto& t:_threads)
        {
            t.run();
        }
    }

    // 返回任务队列是否为空
    bool isEmpty()
    {
        return _tasks.empty();
    }
    // 在条件变量上等待
    void condWait()
    {
        pthread_cond_wait(&_cond, &_lock);
    }

    // 任务队列加锁
    void lockQueue()
    {
        pthread_mutex_lock(&_lock);
    }
    // 任务队列解锁
    void unlockQueue()
    {
        pthread_mutex_unlock(&_lock);
    }
    // 取任务
    T popTask()
    {
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }
    // 唤醒线程
    void wakeTask()
    {
        pthread_cond_signal(&_cond);
    }

    // 线程启动函数
    static void runRountine(void *args)
    {
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);

        while (true)
        {

            // 如果任务队列为空，则在条件变量等待
            tp->lockQueue();

            while (tp->isEmpty())
            {
                tp->condWait();
            }
            T t = tp->popTask();

            tp->unlockQueue();

            t(); // 执行任务

            std::cout << "thread "<<pthread_self()<<" handler done, result: " <<t.formatArg()<<t.formatRes() << std::endl;
        }
    }
    // 放任务
    void pushTask(const T &in)
    {
        lockQueue();

        _tasks.push(in);
        wakeTask(); // 当前肯定有任务，唤醒在条件变量等待的线程

        unlockQueue();
    }

    ~ThreadPool()
    {
        for(auto& t:_threads)
        {
            t.join();
        }

        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<Thread> _threads; // 线程池
    int _num;

    std::queue<T> _tasks;  // 任务列表
    pthread_mutex_t _lock; // 互斥锁
    pthread_cond_t _cond;  // 条件变量
};